package playtools.core;

import java.io.ByteArrayInputStream;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Map;

import playtools.PlayTools;

public enum PlayOperator {
       INSTANCE;
       
       private Map<String, Method> apis = new HashMap<String, Method>();
       private PlayOperator(){
    	   Method[] ms = this.getClass().getMethods();
    	   if(ms != null){
    		   for(Method m: ms){
    			   if((m.getModifiers()|Modifier.PUBLIC) > 0 && m.getName().startsWith("do")){
    				   apis.put(m.getName().substring(2).toLowerCase(), m);
    			   }
    		   }
    	   }
       }

       public Object execute(String cmd, Object... args){
    	   if(PlayTools.checkPlayPath()!= null){
    		   throw new IllegalArgumentException("play path no valid");
    	   }
    	   if(cmd == null){
    		   throw new IllegalArgumentException("command must not be null");
    	   }
    	   if(!apis.containsKey(cmd)){
    		   throw new IllegalArgumentException(MessageFormat.format("command {0} can not be found in PlayOperator:",cmd));
    	   }
    	   Method m = this.apis.get(cmd);
    	   if(!checkParamType(args, m.getParameterTypes())){
    		   throw new IllegalArgumentException(MessageFormat.format("command {0} execute failed, arguments not match in PlayOperator:" ,cmd));
    	   }
    	   try {
			return m.invoke(INSTANCE, args);
		   } catch (Exception e) {
			throw new RuntimeException("execute command '" + cmd +  "' failed!", e);
		   }
       }
       
       private boolean checkParamType(Object[] args, Class<?>[] types){
          if(args.length != types.length){
    		   return false;
    	   }
          for(int i=0; i<args.length; i++){
        	  if(!args[i].getClass().equals(types[i]))
        		  return false;
          }
          return true;
       }
       
       public boolean invokeProc(String[] cmds, String dir){
    	   ProcessStarter starter = new ProcessStarter();
    	   starter.cmds(cmds);
    	   if(dir != null){
    		   starter.pwd(dir);
    	   }
    	   return starter.join(cmds[0]) == 0;
       }
       
       public boolean invokeProcByInput(String[] cmds, String dir, String input){
           ProcessStarter starter = new ProcessStarter();
           starter.cmds(cmds);
           if(dir != null){
               starter.pwd(dir);
           }
           if(input != null)
               starter.stdin(new ByteArrayInputStream(input.getBytes()));
           return starter.join(cmds[0]) == 0;
       }
       
       public boolean doNew(String projName, String appName,  String dir){
    	   return invokeProc(new String[]{PlayTools.getPlayPath(), "new", projName, "--name", appName}, dir);
      }
       
       public boolean doEclipsify(String location){
    	   return invokeProc(new String[]{PlayTools.getPlayPath(), "eclipsify"}, location);
       }
       
       public boolean doDeps(String location){
           return invokeProc(new String[]{PlayTools.getPlayPath(), "deps", "--sync"}, location);
       }
       
       public boolean doInstall(String module){
           return invokeProcByInput(new String[]{PlayTools.getPlayPath(), "install", module}, ".", "y");
       }
}
